﻿using Little.Soldier.SWIFT.Definition;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace Little.Soldier.SWIFT
{
    public abstract class SwiftElement
    {
        internal SwiftElement _Parent;
        internal int _Index;
        private int _Count;

        internal int Index
        {
            get
            {
                return this._Index;
            }
        }

        internal SwiftElement Parent
        {
            get
            {
                return this._Parent;
            }
        }

        internal abstract SwiftDefinitionElement Definition { get; }

        internal SwiftElement(SwiftElement parent, int index)
        {
            this._Parent = parent;
            this._Index = index;
        }

        internal void SetIndex(int index)
        {
            this._Index = index;
        }

        private SwiftMessage GetMessage(SwiftElement swiftElement)
        {
            if (swiftElement is SwiftMessage)
                return swiftElement as SwiftMessage;
            else
                return this.GetMessage(swiftElement.Parent);
        }

        internal virtual SwiftTag GetTag()
        {
            this._Count = 0;
            int index = 0;
            List<SwiftTag> list = this.ListTags(this, this.Definition.Name, ref index);
            this._Count = index;
            if (list.Count > 0)
                return list[0];
            else
                return (SwiftTag) null;
        }

        internal virtual List<SwiftTag> ListTags(SwiftElement element)
        {
            int index = 0;
            return this.ListTags(element, string.Empty, ref index);
        }

        internal virtual List<SwiftTag> ListTags(SwiftElement element, string definitionName, ref int index)
        {
            int beginIndex = 0;
            List<SwiftTag> list = new List<SwiftTag>();
            List<SwiftTag> tags;
            if (this is SwiftMessage && this.Parent == null)
            {
                tags = this.ListTags(((SwiftMessage)this).Block4.Tags, element, ref beginIndex);
            }
            else
            {
                tags = this.Parent.ListTags(this, string.Empty, ref index);
            if (definitionName == string.Empty)
                tags = this.ListTags(tags, element, ref beginIndex);
            }
            index += beginIndex;
            return tags;
        }

        private List<SwiftTag> ListTags(List<SwiftTag> tags, SwiftElement element, ref int beginIndex)
        {
            List<SwiftTag> returnTags = new List<SwiftTag>();
            bool result = false;
            int tagPosition = 0;
            result = this.IsElement(new List<SwiftDefinitionElement>()
            {
            this.Definition
            }, tags, 0, element, (SwiftDefinitionElement) null, ref returnTags, ref result, ref tagPosition, ref beginIndex, false);
            if (!(element is SwiftMessage) && !result)
            returnTags.Clear();
            return returnTags;
        }

        private bool IsElement(List<SwiftDefinitionElement> elementsDefinition, List<SwiftTag> tags, int depth, SwiftElement returnSwiftElement, SwiftDefinitionElement parentDefinitionElement, ref List<SwiftTag> returnTags, ref bool result, ref int tagPosition, ref int returnElementIndex, bool foundElement)
        {
            int num1 = depth++;
            using (List<SwiftDefinitionElement>.Enumerator enumerator = elementsDefinition.GetEnumerator())
            {
        label_37:
            if (enumerator.MoveNext())
            {
                SwiftDefinitionElement current = enumerator.Current;
                if (!foundElement && result)
                return result;
                if (tags.Count == tagPosition)
                {
                if (returnElementIndex == 0)
                    returnElementIndex = tagPosition;
                return result;
                }
                else
                {
                int num2 = tagPosition;
                int num3 = -1;
                while (!result || !(returnSwiftElement.Definition is SwiftTagDefinition))
                {
                    ++num3;
                    if (returnSwiftElement.Definition == current && result)
                    return result;
                    if (returnSwiftElement.Definition == current && num3 == returnSwiftElement.Index)
                    {
                    result = true;
                    returnTags.Clear();
                    returnElementIndex = tagPosition;
                    }
                    if (current is SwiftTagDefinition)
                    {
                    string str = ((SwiftTagDefinition) current).TagName.ToLower();
                    List<string> list = new List<string>();
                    list.Add(string.Format(":{0}:", (object) tags[tagPosition].Name.ToLower()));
                    list.Add(string.Format(":{0}::", (object) tags[tagPosition].Name.ToLower()));
                    list.Add(string.Format(":{0}:/", (object) tags[tagPosition].Name.ToLower()));
                    if (list.Contains(":16r:") || list.Contains(":16s:"))
                    {
                        list.Clear();
                        list.Add(string.Format(":{0}:{1}", (object) tags[tagPosition].Name.ToLower(), (object) tags[tagPosition].Value.Trim().ToLower()));
                    }
                    if (list.Contains(str))
                    {
                        returnTags.Add(tags[tagPosition]);
                        ++tagPosition;
                    }
                    else if ((!(parentDefinitionElement is SwiftTagChoiceDefinition) || parentDefinitionElement is SwiftTagChoiceDefinition && elementsDefinition[elementsDefinition.Count - 1] == current) && current.Mandatory)
                    {
                        if (!(current is SwiftTagDefinition) || !((SwiftTagDefinition) current).Multiple)
                        return result;
                        else
                        goto label_37;
                    }
                    }
                    else if (current is SwiftMessageDefinition)
                        result = this.IsElement(current.Elements, tags, depth, returnSwiftElement, current, ref returnTags, ref result, ref tagPosition, ref returnElementIndex, result);
                    else if (current is SwiftTagSequenceDefinition)
                        result = this.IsElement(current.Elements, tags, depth, returnSwiftElement, current, ref returnTags, ref result, ref tagPosition, ref returnElementIndex, result);
                    else if (current is SwiftTagChoiceDefinition)
                        result = this.IsElement(current.Elements, tags, depth, returnSwiftElement, current, ref returnTags, ref result, ref tagPosition, ref returnElementIndex, result);
                    bool flag;
                    if (current is SwiftTagSequenceDefinition && ((SwiftTagSequenceDefinition) current).Multiple || current is SwiftTagDefinition && ((SwiftTagDefinition) current).Multiple)
                    {
                    if (num2 != tagPosition)
                    {
                        num2 = tagPosition;
                        flag = true;
                    }
                    else
                        flag = false;
                    if (tags.Count == tagPosition)
                        flag = false;
                    }
                    else
                    {
                    num2 = tagPosition;
                    flag = false;
                    }
                    if (!flag)
                    goto label_37;
                }
                return result;
                }
            }
            }
            return result;
        }

        internal virtual void AddTag(SwiftTag tag)
        {
            if (this.GetTag() != null)
            throw new Exception();
            SwiftMessage message = this.GetMessage(this);
            if (this._Count >= message.Block4.Tags.Count)
            message.Block4.Tags.Add(tag);
            else
            message.Block4.Tags.Insert(this._Count, tag);
        }

        internal void RemoveTag(SwiftTag tag)
        {
            this.GetMessage(this).Block4.Tags.Remove(tag);
        }

        internal void InitSwiftSwiftElement(SwiftDefinitionElement definitionElement, SwiftElement element)
        {
            this.GetListElements(new List<SwiftDefinitionElement>()
            {
                definitionElement
            }, element, false);
        }

        internal List<string> GetListElements(List<SwiftDefinitionElement> elementsDefinition, SwiftElement element, bool isChoice)
        {
            List<string> list = new List<string>();
            foreach (SwiftDefinitionElement definitionElement in elementsDefinition)
            {
            if (definitionElement is SwiftTagDefinition && definitionElement.Mandatory)
            {
                PropertyInfo property1 = element.GetType().GetProperty(definitionElement.Name);
                SwiftElement swiftElement = !((SwiftTagDefinition) definitionElement).Multiple ? (SwiftElement) property1.GetValue((object) element, (object[]) null) : (SwiftElement) element.GetType().GetMethod("Add" + property1.Name).Invoke((object) element, (object[]) null);
                PropertyInfo property2 = swiftElement.GetType().GetProperty("Value");
                definitionElement.Name.Substring(definitionElement.Name.LastIndexOf("_") + 1);
                string str = string.Empty;
                int num = ((SwiftTagDefinition) definitionElement).TagName.LastIndexOf(":");
                if (num + 1 < ((SwiftTagDefinition) definitionElement).TagName.Length)
                str = ((SwiftTagDefinition) definitionElement).TagName.Substring(num + 1);
                property2.SetValue((object) swiftElement, (object) str, (object[]) null);
                if (isChoice)
                break;
            }
            else if (definitionElement is SwiftMessageDefinition)
                list.AddRange((IEnumerable<string>)this.GetListElements(definitionElement.Elements, element, false));
            else if (definitionElement is SwiftTagSequenceDefinition && definitionElement.Mandatory)
            {
                PropertyInfo property = element.GetType().GetProperty(definitionElement.Name);
                SwiftTagSequence[] swiftTagSequenceArray = (SwiftTagSequence[]) null;
                SwiftTagSequence swiftTagSequence1 = (SwiftTagSequence) null;
                if (((SwiftTagSequenceDefinition) definitionElement).Multiple)
                swiftTagSequenceArray = (SwiftTagSequence[]) property.GetValue((object) element, (object[]) null);
                else
                swiftTagSequence1 = (SwiftTagSequence) property.GetValue((object) element, (object[]) null);
                if (swiftTagSequenceArray != null)
                {
                if (swiftTagSequenceArray.GetLength(0) == 0)
                {
                    element.GetType().GetMethod("Add" + definitionElement.Name).Invoke((object) element, (object[]) null);
                    swiftTagSequenceArray = (SwiftTagSequence[]) property.GetValue((object) element, (object[]) null);
                }
                foreach (SwiftTagSequence swiftTagSequence2 in swiftTagSequenceArray)
                    list.AddRange((IEnumerable<string>)this.GetListElements(definitionElement.Elements, (SwiftElement)swiftTagSequence2, false));
                }
                else
                {
                if (swiftTagSequence1 == null)
                    throw new Exception();
                list.AddRange((IEnumerable<string>)this.GetListElements(definitionElement.Elements, (SwiftElement)swiftTagSequence1, false));
                }
            }
            else if (definitionElement is SwiftTagChoiceDefinition && definitionElement.Mandatory)
                list.AddRange((IEnumerable<string>)this.GetListElements(definitionElement.Elements, element, true));
            }
            return list;
        }
    }
}
